<template>
  <view
    class="flex"
    :class="[
      props.direction == 'vertical' ? 'flex-row' : '',
      _disabled ? 'opacity-6' : '',
    ]"
  >
    <view
      class="relative flex flex-col"
      :class="[
        props.direction == 'horizontal'
          ? 'flex-col-center-start'
          : 'flex-row-center-center',
      ]"
      :style="[
        { width: _sliderBarCssWidth + 'rpx', height: _sliderBarCssHeight + 'rpx' },
      ]"
    >
      <tm-sheet
        noLevel
        :round="10"
        :color="props.bgColor"
        :height="props.direction == 'horizontal' ? props.height : _sliderBarCssHeight"
        :width="props.direction == 'horizontal' ? _sliderBarCssWidth : props.height"
        :margin="[0, 0]"
        :padding="[0, 0]"
      ></tm-sheet>
      <slider-bar
        :followTheme="props.followTheme"
        :class="[
          props.direction == 'horizontal'
            ? 'flex-col-center-start'
            : 'flex-row-center-center',
        ]"
        :direction="props.direction"
        :color="props.color"
        :size="props.height"
        :x="_barLet"
        :width="_barWidth"
      ></slider-bar>
      <slider-mask
        :followTheme="props.followTheme"
        :color="props.color"
        v-if="props.showLabel"
        :size="props.buttonSize"
        :step="props.step"
        :min="props.min"
        :max="props.max"
        :width="_sliderBarCssWidth"
        :height="_sliderBarCssHeight"
        :direction="props.direction"
      ></slider-mask>
      <slider-button
        :maxLeft="buttonStaticsMaxLeft"
        :followTheme="props.followTheme"
        :direction="props.direction"
        ref="btn0"
        :color="props.color"
        :x="btnPos[0].x"
        @movestart="butnMoveStart($event, 0)"
        @moveing="butnMove($event, 0)"
        @moveend="butnMoveEnd($event, 0)"
        :size="props.buttonSize"
      ></slider-button>
      <slider-button
        :maxLeft="buttonStaticsMaxLeft"
        :followTheme="props.followTheme"
        :direction="props.direction"
        v-if="isDablue"
        ref="btn1"
        :color="props.color"
        :x="btnPos[1].x"
        @movestart="butnMoveStart($event, 1)"
        @moveing="butnMove($event, 1)"
        @moveend="butnMoveEnd($event, 1)"
        :size="props.buttonSize"
      ></slider-button>
    </view>
    <view
      v-if="props.showLabel"
      :class="[props.direction == 'vertical' ? 'flex-col' : 'flex-row']"
    >
      <slider-label
        :size="props.buttonSize"
        :step="props.step"
        :min="props.min"
        :max="props.max"
        :width="_sliderBarCssWidth"
        :height="_sliderBarCssHeight"
        :direction="props.direction"
      ></slider-label>
    </view>
    <view
      v-if="showDetail"
      class="flex absolute"
      :class="[
        props.direction == 'horizontal' ? 'flex-col flex-col-start-center' : ' flex-row ',
      ]"
      :style="[
        props.direction == 'horizontal'
          ? { width: props.width + props.buttonSize + 'rpx' }
          : { height: props.width + props.buttonSize + 'rpx' },
      ]"
    >
      <view
        :class="[
          isNvue ? 'fixed' : 'absolute ',
          props.direction == 'horizontal' ? (isNvue ? 't-0' : 'b-0') : 't-0 ',
        ]"
        class="mb-0 flex flex-col flex-col-bottom-center"
        :style="[
          !isNvue
            ? props.direction == 'horizontal'
              ? {
                  transform: `translateX(${btnPos[BtnIndex].x}px)`,
                  left: -(100 - props.buttonSize + 24) / 2 + 'rpx',
                }
              : {
                  transform: `translateY(${btnPos[BtnIndex].x}px)`,
                  top: '-70rpx',
                  left: -(100 - props.buttonSize + 24) / 2 + 'rpx',
                }
            : { left: `${nvueDetailPos.left}px`, top: `${nvueDetailPos.bottom}px` },
        ]"
      >
        <tm-sheet
          _class="flex-center"
          color="grey-darken-5"
          :border="2"
          :margin="[0, 0]"
          :padding="[10, 6]"
          :width="100"
          :round="3"
        >
          <tm-text :label="_value"></tm-text>
        </tm-sheet>
        <tm-icon
          color="grey-darken-5"
          _class=""
          :font-size="32"
          name="tmicon-sort-down-nogap-copy"
        ></tm-icon>
      </view>
    </view>
  </view>
</template>
<script lang="ts" setup>
/**
 * 滑块
 * description 注意，如果想开启单滑块（默认），default-value=0单个值即可，如果想双滑块，值等于数组比如:=[0,5]
 */
import {
  computed,
  ref,
  Ref,
  toRaw,
  getCurrentInstance,
  watchEffect,
  watch,
  inject,
} from "vue";
import { inputPushItem, rulesItem } from "./../tm-form-item/interface";
import sliderBar from "./slider-bar.vue";
import sliderButton from "./slider-button.vue";
import tmSheet from "../tm-sheet/tm-sheet.vue";
import tmText from "../tm-text/tm-text.vue";
import TmIcon from "../tm-icon/tm-icon.vue";
import sliderLabel from "./slider-label.vue";
import sliderMask from "./slider-mask.vue";
// #ifdef APP-PLUS-NVUE
const dom = uni.requireNativePlugin("dom");
// #endif
const btn0 = ref<InstanceType<typeof sliderButton> | null>(null);
const btn1 = ref<InstanceType<typeof sliderButton> | null>(null);

const proxy = getCurrentInstance()?.proxy ?? null;
const emits = defineEmits(["update:modelValue", "change"]);
const props = defineProps({
  //是否跟随全局主题的变换而变换
  followTheme: {
    type: [Boolean, String],
    default: true,
  },
  //竖向时这个是高度。
  width: {
    type: Number,
    default: 500,
  },
  // 条的高度
  //竖向时，这个是宽度。
  height: {
    type: Number,
    default: 8,
  },
  //按钮的大小。
  buttonSize: {
    type: Number,
    default: 52,
  },
  /**
   * 方向
   * horizontal:水平,
   * vertical:竖向。
   */
  direction: {
    type: String,
    default: "horizontal",
  },
  color: {
    type: String,
    default: "primary",
  },
  bgColor: {
    type: String,
    default: "grey-3",
  },
  max: {
    type: Number,
    default: 100,
  },
  min: {
    type: Number,
    default: 0,
  },
  //默认的值一定要和v-model相同的类型，
  defaultValue: {
    type: [Array, Number],
    default: 0,
  },

  //双向绑定数据可以使用v-model,记住格式一定要和defaultValue相同。
  modelValue: {
    type: [Array, Number],
    default: 0,
  },
  //格式为自己的标签显示 ，是按钮上方的显示 标签。
  formart: {
    type: Function,
    default: () => {
      return (val: number | string) => {
        return val;
      };
    },
  },
  //只有这个为true,下面的step才会显示标签。
  showLabel: {
    type: Boolean,
    default: false,
  },
  //需要显示的步骤标签。
  step: {
    type: Number,
    default: 5,
  },
  disabled: {
    type: Boolean,
    default: false,
  },
});

interface btnMovetype {
  x: number;
  y: number;
}
const width = computed(() => uni.upx2px(props.width));
const isDarg = ref(false);
const _disabled = computed(() => props.disabled);
const btnPos: Ref<Array<btnMovetype>> = ref([
  {
    x: 0,
    y: 0,
  },
  {
    x: 0,
    y: 0,
  },
]);
let _x = 0;
let _y = 0;
let buttonStaticsLeft = 0;
let buttonStaticsMaxLeft = width.value;
const isNvue = ref(false);
const nvueDetailPos = ref({ left: 0, bottom: 0 });
// #ifdef APP-NVUE
isNvue.value = true;
// #endif

const _sliderBarCssWidth = computed(() => {
  if (props.direction == "horizontal") return props.width + props.buttonSize;
  return props.buttonSize;
});
const _sliderBarCssHeight = computed(() => {
  if (props.direction == "horizontal") return props.buttonSize;
  return props.width + props.buttonSize;
});

//当前操作的是哪个按钮。
const BtnIndex = ref(0);
//显示上访值。
const showDetail = ref(false);
const _valueMax = computed(() => {
  return props.max - props.min;
});
const _barWidth = computed(() => {
  return Math.abs(btnPos.value[0].x - btnPos.value[1].x);
});
const _barLet = computed(() => {
  return Math.min(Math.abs(btnPos.value[0].x), Math.abs(btnPos.value[1].x));
});

const _value = ref(0);
//是双滑块，还是单滑块。
const isDablue = ref(false);
if (typeof props.defaultValue == "object" && Array.isArray(props.defaultValue)) {
  isDablue.value = true;
}
zhuanghuaValue();
watchEffect(() => {
  let val = Math.ceil(
    (Math.abs(btnPos.value[BtnIndex.value].x) / uni.upx2px(props.width)) *
      _valueMax.value +
      props.min
  );
  if (typeof props.formart === "function") {
    let p = props.formart(val);
    if (typeof p === "function") {
      p = p(val);
    }
    val = p;
  }
  _value.value = val;
});
emits("update:modelValue", getValue());
const _blackValue = getValue();
watch(
  () => props.modelValue,
  () => {
    if (!isDablue.value) {
      btnPos.value[0].x = Math.abs(
        (Number(props.modelValue) / _valueMax.value) * uni.upx2px(props.width)
      );
    } else {
      btnPos.value[0].x = Math.abs(
        (Number(props.modelValue[0]) / _valueMax.value) * uni.upx2px(props.width)
      );
      btnPos.value[1].x = Math.abs(
        (Number(props.modelValue[1]) / _valueMax.value) * uni.upx2px(props.width)
      );
    }
  }
);

function zhuanghuaValue() {
  if (!isDablue.value) {
    let vsp = Number(props.defaultValue);
    vsp = vsp >= _valueMax.value ? _valueMax.value : vsp;
    vsp = vsp <= props.min ? props.min : vsp;
    let vl = Math.abs((vsp / _valueMax.value) * uni.upx2px(props.width));
    btnPos.value[0].x = vl;
  } else {
    let vsp_0 = Number(props.defaultValue[0]);
    vsp_0 = vsp_0 >= _valueMax.value ? _valueMax.value : vsp_0;
    vsp_0 = vsp_0 <= props.min ? props.min : vsp_0;
    let vl_0 = Math.abs((vsp_0 / _valueMax.value) * uni.upx2px(props.width));
    btnPos.value[0].x = vl_0;

    let vsp_1 = Number(props.defaultValue[1]);
    vsp_1 = vsp_1 >= _valueMax.value ? _valueMax.value : vsp_1;
    vsp_1 = vsp_1 <= props.min ? props.min : vsp_1;
    let vl_1 = Math.abs((vsp_1 / _valueMax.value) * uni.upx2px(props.width));
    btnPos.value[1].x = vl_1;
  }
}

function getValue() {
  if (!isDablue.value) {
    return Math.ceil(
      (Math.abs(btnPos.value[0].x) / uni.upx2px(props.width)) * _valueMax.value +
        props.min
    );
  } else {
    return [
      Math.ceil(
        (Math.abs(btnPos.value[0].x) / uni.upx2px(props.width)) * _valueMax.value +
          props.min
      ),
      Math.ceil(
        (Math.abs(btnPos.value[1].x) / uni.upx2px(props.width)) * _valueMax.value +
          props.min
      ),
    ];
  }
}

function butnMoveStart(e: btnMovetype, index: number) {
  if (props.disabled) return;
  isDarg.value = true;

  if (props.direction == "horizontal") {
    _x = e.x - btnPos.value[index].x;
  } else {
    _x = e.y - btnPos.value[index].x;
  }

  BtnIndex.value = index;
}
function butnMove(e: btnMovetype, index: number) {
  if (props.disabled) return;
  if (!isDarg.value) return;
  let left = e.x - _x;
  if (props.direction != "horizontal") {
    left = e.y - _x;
  }
  if (left < buttonStaticsLeft) {
    left = buttonStaticsLeft;
  } else if (left > buttonStaticsMaxLeft) {
    left = buttonStaticsMaxLeft;
  }

  btnPos.value[index].x = left;
  showDetail.value = true;
  getDomRectBound();
}
function butnMoveEnd(e: btnMovetype, index: number) {
  if (props.disabled) return;
  isDarg.value = false;
  showDetail.value = false;
  emits("update:modelValue", getValue());
  emits("change", getValue());
}

function getDomRectBound() {
  // #ifdef APP-NVUE
  dom.getComponentRect(proxy?.$refs["btn" + BtnIndex.value], function (res) {
    if (res?.size) {
      // { ...res.size }
      // console.log(res.size)
      const { left, top } = res.size;
      nvueDetailPos.value = {
        left: left - (uni.upx2px(100) - uni.upx2px(props.buttonSize)) / 2,
        bottom: top - 45,
      };
    }
  });
  // #endif
}
</script>
<style scoped></style>
